import {Injectable} from '@angular/core';

import {Subject} from 'rxjs';
import {Observable} from 'rxjs';

import * as io from 'socket.io-client';
import feathers from '@feathersjs/client';
import {
    InterfaceRequestClient,
    LangInterface,
    ObservablesInterface,
    RequestInterface
} from './interface-request-client';
import {ApiService} from '../app/api.service';

@Injectable()
export class RequestClientService extends ApiService {
//this.request.requset({client:'transactions',request:{clientName:'find'},clientConfig:{timout:30000},isAuth:true})
    public request$: Observable<any>;
    public language: string;
    public authPromise: any;
    public client: any;

    protected clientSerive: any;
    protected requestClientSubject: Subject<any>;
    protected DataPools: any;

    constructor() {
        super();
        this.requestClientSubject = new Subject<any>();
        const socket = io(this.url);
        const client = feathers();
        client.configure(feathers.socketio(socket));
        client.configure(feathers.authentication({
            storageKey: this.storageKey,
            storage: this.storage
        }));
        this.client = client;
        if (this.isLogin()) {
            this.getAuthPromise();
        }

        // 配置语言信息
        let langs = this.storage.getItem(this.langStorageName);


        if (langs == 'en' || langs == 'zh')
            this.language = langs;
        else
            this.language = this.setLangMessage({type: 'en'});

        this.request$ = this.requestClientSubject.asObservable();


    }

    /**
     * remove  id data
     * @param {RequestInterface} Inter
     * @returns {Promise<any>}
     */


    /**
     *
     * @param {RequestInterface} Inter
     * @returns {Promise<any>}
     */

    protected async find(Inter: RequestInterface) {
        try {
            let success = await  this.clientSerive.find(Inter.params);
            return success;
        } catch (e) {
            throw this.getErrors(e);
        }
    }

    protected async get(Inter: RequestInterface) {
        try {
            let success = await this.clientSerive.get(Inter.id ? Inter.id : null, Inter.params);
            return success;
        } catch (e) {
            throw this.getErrors(e);
        }

    }

    protected async create(Inter: RequestInterface) {
        try {
            if (!Inter.data) throw this.getErrors(null, 'data is requied');
            let success = await this.clientSerive.create(Inter.data, Inter.params);
            return success;
        } catch (e) {
            throw this.getErrors(e);
        }
    }

    protected async patch(Inter: RequestInterface) {
        try {
            if (!Inter.data) throw  this.getErrors(null, 'update There must be a data field');
            let success = await  this.clientSerive.patch(Inter.id ? Inter.id : null, Inter.data, Inter.params);
            return success;
        } catch (e) {
            throw e;
        }
    }

    protected async update(Inter: RequestInterface) {
        try {
            console.log(Inter.data);
            if (!Inter.id) throw  this.getErrors(null, 'update There must be a ID field');
            if (!Inter.data) throw  this.getErrors(null, 'update There must be a data field');
            let success = await  this.clientSerive.update(Inter.id, Inter.data, Inter.params);
            return success;
        } catch (e) {
            throw e;
        }
    }

    public async getUser(observables?: ObservablesInterface) {
        try {
            this.getAuthPromise();
            let success = await this.authPromise;
            if (observables) {
                this.setSubjectNext(observables.code ? observables.code : '200',
                    observables.ObservableName ? observables.ObservableName : 'subject-default',
                    success);
            }
            return success;
        } catch (e) {
            throw this.getErrors(e);
        }
    }

    public setLangMessage(typeInterface: LangInterface): string {
        this.storage.setItem(this.langStorageName, typeInterface.type);
        return typeInterface.type;
    }

    public async login(model: any, code: string) {
        return this.client.authenticate({
            strategy: 'local',
            email: model.email,
            password: model.password,
            code: code
        }).then((user) => {
            this.storage.setItem(this.storageKey, user.accessToken);
            this.setSubjectNext(code, 'login', user);
            this.getAuthPromise();
            return user;
        }).catch((error) => {
            if(error.code == 401)
            this.loginOut();
            throw this.getErrors(error);
        });
    }

    public setSubjectNext(code, name, data: any) {
        this.requestClientSubject.next({
            code: code,
            name: name,
            data: data
        });
    }


    public async requset(interfaces: InterfaceRequestClient) {
        try {
            if (!interfaces) throw this.getErrors(null, this.language == 'zh' ? '实参不能为空!..' : 'interface is not null');
            if (interfaces.isAuth) {
                // if (!this.authPromise) {
                this.getAuthPromise();
                // }
                await this.authPromise;
            }
        } catch (e) {
            if (e.code==401)
            this.loginOut();
            throw this.getErrors(e);

        }
        this.clientSerive = this.client.service(interfaces.client);
        if (interfaces.clientConfig)
            if (interfaces.clientConfig.timout)
                this.clientSerive.timeout = interfaces.clientConfig.timout;
        let success;
        switch (interfaces.request.clientName) {
            case 'find':
                try {
                    success = await this.find(interfaces.request);
                } catch (e) {
                    throw this.getErrors(e);
                }
                break;
            case 'update':
                try {
                    success = await this.update(interfaces.request);
                } catch (e) {
                    throw this.getErrors(e);
                }
                break;
            case 'patch':
                try {
                    success = await this.patch(interfaces.request);
                } catch (e) {
                    throw this.getErrors(e);
                }
                break;
            case 'get':
                try {
                    success = await this.get(interfaces.request);
                } catch (e) {
                    throw this.getErrors(e);
                }
                break;
            case 'create':
                try {
                    success = await this.create(interfaces.request);

                } catch (e) {
                    throw this.getErrors(e);
                }
                break;
            case 'login':
                try {
                    success = await this.login(interfaces.request.params, interfaces.request.id);
                } catch (e) {
                    throw this.getErrors(e);
                }
                break;
        }
        if (success)
            if (interfaces.Observables)
            // if (interfaces.Observables.ObservableName)
                this.setSubjectNext(interfaces.Observables.code ? interfaces.Observables.code : '200', interfaces.Observables.ObservableName ? interfaces.Observables.ObservableName : 'subject-default', success);

        if (interfaces.loggerTag)
            this.outLogger(interfaces.loggerTag, success);
        else
            this.outLogger('request' + interfaces.client, success);
        return success;
    }


    public isLogin(): boolean {
        let value = this.storage.getItem(this.storageKey);

        return value != null && value != '';
    }

    public loginOut(): void {
        //delete this.storage[this.storageKey];
        this.client.logout();
        window.location.reload();
    }

    public getErrors(error: any, parameterError?: string): string {
        if (parameterError)
            return parameterError;
        if (this.FeathersError[error.code] == undefined) {
            if (this.language == 'en') {
                return error.message;
            } else if (this.language == 'zh') {
                return error.data;
            }
        } else {
            if (this.language == 'en') {
                return this.FeathersError[error.code].message_en;
            } else if (this.language == 'zh') {
                return this.FeathersError[error.code].message_zh;
            }
        }

    }

    public getSucc(message: any): string {
        if (this.language == 'en') {
            return message.en;
        }
        if (this.language == 'zh') {
            return message.zh;
        }
    }

    protected getAuthPromise() {
        this.authPromise = this.client.authenticate();
    }
}
